package com.pt25.base.dep.redis;


import com.pt25.base.constants.BaseConstants;
import com.pt25.base.util.StrUtil;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RBatch;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.redisson.client.codec.StringCodec;
import org.springframework.stereotype.Service;

import java.time.Duration;
import java.util.Map;
import java.util.concurrent.TimeUnit;

@Slf4j
@Service
public class RedisService {

    private static final Integer sixtySeconds = 60;

    private static final String autoIncrIdPre = "auto_incr_id&";
    private static final String lockKeyPre = "aim-global-lock-key&";
    private static final String lockKeyData = "aim-global-lock-data&";

    @Resource
    private Map<String, RedissonClient> redissonClientMap;

    /**
     * 获取默认redis集群RedissonClient
     */
    public RedissonClient getRedissonClient() {
        return redissonClientMap.get(BaseConstants.DEFAULT);
    }

    /**
     * 根据redisName获取redis集群RedissonClient
     *
     * @param redisName redis集群名称
     */
    public RedissonClient getRedissonClient(String redisName) {
        if (StrUtil.isBlank(redisName)) {
            return getRedissonClient();
        }
        return redissonClientMap.get(redisName);
    }


    /**
     * 非阻塞锁，未获取到锁会直接返回false，不会阻塞
     *
     * @param key       缓存key
     * @param redisName redis集群名称
     */
    public boolean unblockLock(String redisName, String key) {
        RedissonClient redissonClient = getRedissonClient(redisName);
        String lockKey = lockKeyPre + key;
        String lockData = lockKeyData + key;
        long nowTimes = System.currentTimeMillis();
        RLock lock = redissonClient.getLock(lockKey);
        boolean isLocked = false;
        try {
            isLocked = lock.tryLock(sixtySeconds, TimeUnit.SECONDS);
            if (isLocked) {
                Object lastTimesObj = redissonClient.getBucket(lockData, new StringCodec()).get();
                if (null == lastTimesObj || nowTimes > Long.parseLong(lastTimesObj.toString())) {
                    RBatch batch = redissonClient.createBatch();
                    batch.getBucket(lockData, new StringCodec()).setAsync(nowTimes + 1000);
                    batch.getBucket(lockData, new StringCodec()).expireAsync(Duration.ofSeconds(sixtySeconds));
                    batch.execute();
                    return true;
                }
            }
        } catch (Exception e) {
            log.info("RedisUtil-lock-error=", e);
        } finally {
            if (isLocked) {
                lock.unlock();
            }
        }
        return false;
    }

    /**
     * 全局自增ID递增
     */
    public Long genAutoIncrID(String redisName, String key) {
        return getRedissonClient(redisName).getAtomicLong(autoIncrIdPre + key).incrementAndGet();
    }


}
